package org.dbp.registros;

import java.beans.PropertyEditorSupport;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.dbp.error.ErrorDbpUtils;
import org.dbp.error.exception.ExceptionDbp;
import org.dbp.reflexion.ClassDbpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * Esta clase utilidades, para los registros.
 * 
 * @author dbp
 *
 */
public class RegistroDbpUtils {

	private static Logger logger = LoggerFactory.getLogger(RegistroDbpUtils.class);
	
	private ClassDbpUtils classDbpUtils; 
	
	private static RegistroDbpUtils instancia = new RegistroDbpUtils();
	
	public static RegistroDbpUtils obtenerInstancia(){
		return instancia;
	}
	
	
	public RegistroDbpUtils() {
		super();
		classDbpUtils=ClassDbpUtils.obtenerInstancia();
	}


	/**
	 * 
	 * Se encarga de procesar la excepci�n generica para los m�todos de register propertyes.
	 * 
	 * @param error			El mensaje con el error que se ha producido.
	 * @param loggerClase	El logger de la clase donde se ha ejecutado, para que tengamos la traza.
	 */
	public void procesarError(String error,Logger loggerClase){
		procesarError(error,null,loggerClase);
	}
	
	/**
	 * Se encarga de procesar la excepci�n generica para los m�todos de register propertyes.
	 * 
	 * Que tienen que estar recubiertos por la exception (IllegalArgumentException)
	 * @param error			El mensaje con el error que se ha producido.
	 * @param exception		La exception que ha probacado el error.
	 * @param loggerClase	El logger de la clase donde se ha ejecutado, para que tengamos la traza.
	 */
	public void procesarError(String error,Throwable exception,Logger loggerClase){
		if(exception!=null){
			loggerClase.error(error,exception);
			throw new IllegalArgumentException(error, exception);
		}else{
			loggerClase.error(error);
			throw new IllegalArgumentException(error);
		}
	}
	
	/**
	 * 
	 * Se encarga de obtener el valor en formato de texto, de un campo de un objeto.
	 * 
	 * @param definicionRegistros	Aqui estan definidos los registros encargados de parsear los datos.
	 * @param entidad				El objeto de domode vamos a obtener los datos.
	 * @param campo					El nombre del campo del que vamos a obtener los datos.
	 * @param clase					La clase del campo en cuesti�n.
	 * @return						Nos devuelve el texto formateado por los registros.
	 * @throws ExceptionGridDbp 
	 */
	public <T extends Serializable> String obtenerLaCadenaDeTexto(Map<Class<?>,PropertyEditorSupport> definicionRegistros,T entidad
			, String campo, Class<?> clase) throws ExceptionDbp{
		String valdev=null;
		if(definicionRegistros==null){
			ErrorDbpUtils.obtenerInstancia().procesarError(logger
					, "La definicion de los registros es ["+definicionRegistros+"]");
		}else if(entidad==null){
			ErrorDbpUtils.obtenerInstancia().procesarError(logger
					, "La definicion de la entidad es ["+entidad+"]");			
		}else if(campo==null){
			ErrorDbpUtils.obtenerInstancia().procesarError(logger
					, "La definicion del campo es ["+campo+"]");
		}else if(clase==null){
			ErrorDbpUtils.obtenerInstancia().procesarError(logger
					, "La definicion de la clase es ["+clase+"]");
		}else{
			valdev= procesarObtenerLaCadenaDeTexto(definicionRegistros,
				entidad, campo, clase);
		}
		return valdev;
	}
	/**
	 * Se encarga de procesar la obteneci�n de la cadena
	 *  
	 * @param definicionRegistros	Aqui estan definidos los registros encargados de parsear los datos.
	 * @param entidad				El objeto de domode vamos a obtener los datos.
	 * @param campo					El nombre del campo del que vamos a obtener los datos.
	 * @param clase					La clase del campo en cuesti�n.
	 * @return
	 * @throws ExceptionGridDbp
	 */
	private <T extends Serializable> String procesarObtenerLaCadenaDeTexto(
			Map<Class<?>, PropertyEditorSupport> definicionRegistros,
			T entidad, String campo, Class<?> clase )
			throws ExceptionDbp {
		String valorCadena =null;
		try {
			Object valor=PropertyUtils.getProperty(entidad, campo);
			PropertyEditorSupport propertyEditorSupport= definicionRegistros.get(clase);
			if(propertyEditorSupport==null){
				ErrorDbpUtils.obtenerInstancia().procesarError(logger
						, "Para la clase ["+clase+"] no tenemos registro declarado");
			}else{
				if(valor==null){
					valorCadena="";
				}else if(classDbpUtils.iguales(valor.getClass(), clase, true)){
					propertyEditorSupport.setValue(valor);
					valorCadena=propertyEditorSupport.getAsText();
				}else{
					String codigoError="DU-ERROR:1000";
					if(logger.isDebugEnabled()){
						debugErrorDuError1000(definicionRegistros, entidad,
								campo, clase, codigoError);
					}
					ErrorDbpUtils.obtenerInstancia().procesarError(logger
						, codigoError+" La clase del campo ["+valor.getClass().getName()+"] es distinta a la que nos han indicado ["+clase.getName()+"]");
				}
			}
		} catch (IllegalAccessException | InvocationTargetException
				| NoSuchMethodException e) {
			String error="Se ha producido el error ["+e.getLocalizedMessage()+"] al procesar el campo ["+campo
					+"], en la entidad ["+(entidad==null?entidad:entidad.getClass().getName())+"] al intentar obtener la cadena texto del valor del campo "; 
			ErrorDbpUtils.obtenerInstancia().procesarError(logger, error, e);
		}
		return valorCadena;
	}
	/**
	 * 
	 * Este método se encarga de mostrarnos la información correspondiente al error en los tipos de datos.
	 * 
	 * @param definicionRegistros
	 * @param entidad
	 * @param campo
	 * @param clase
	 * @param codigoError
	 */
	private <T extends Serializable> void debugErrorDuError1000(
			Map<Class<?>, PropertyEditorSupport> definicionRegistros,
			T entidad, String campo, Class<?> clase, String codigoError) {
		logger.debug("{}: INICIO Datos de procesamos del error",codigoError);
		logger.debug("  *Parametros de entrada");
		logger.debug("   - Definicion Registros [{}]",definicionRegistros);
		logger.debug("   - Entidad [{}], detallada [{}]",entidad,entidad!=null?ToStringBuilder.reflectionToString(entidad,ToStringStyle.MULTI_LINE_STYLE):entidad);
		logger.debug("   - Campo [{}], es el nombre del campo del que vamos a obtener los datos ",campo);
		logger.debug("   - Clase [{}], la clase con la que estamos trabajando.",clase);
		logger.debug("	*Registros configurados");
		for(Class<?> clave : definicionRegistros.keySet()){
			logger.debug("      - Tenemos un registros [{}]",clave);
		}
		logger.debug("  * Soluciones");
		logger.debug("     - Esto sucede por que el objeto instancia en le atributo es un hijo del objeto definido (Puede pasar con un ORM)");
		logger.debug("     - Error en la definicion de la clase que nos pasan y la definicion real del campo del objeto reviselos");
		logger.debug("{}: FIN Datos de procesamos del error",codigoError);
	}
	
}
